"""
Author: runyu.ma

ast_walker.py
"""

from ..core.dslc_parser import BlockOp, BinaryOp, UnaryOp


def merge_block_content(ast: BlockOp, consumer):
    """
    不处理嵌套的merge
    合并Block中可能合并的内容，因为整个ast都在一个BlockOp中，所以可以处理最外层
    """
    return __merge_block_content(ast, consumer, nested=False)


def merge_nested_block_content(ast: BlockOp, consumer):
    """
    合并Block中可能合并的内容，因为整个ast都在一个BlockOp中，所以可以处理最外层
    """
    return __merge_block_content(ast, consumer, nested=True)


def __merge_block_content(ast: BlockOp, consumer, nested=False):
    """
    递归合并下面的内容
    """
    if isinstance(ast, UnaryOp):
        blkop = __merge_block_content(ast.x, consumer, nested=nested)
        return UnaryOp(ast.op, blkop)
    if isinstance(ast, BinaryOp):
        #print(ast)
        lop = __merge_block_content(ast.l, consumer, nested=nested)
        rop = __merge_block_content(ast.r, consumer, nested=nested)
        return BinaryOp(ast.op, lop, rop)
    if not isinstance(ast, BlockOp):
        return ast
    idx = -1
    oplist = []
    while idx < len(ast.oplist)-1:# loop ast.oplist
        idx += 1
        it = ast.oplist[idx]
        if isinstance(it, BlockOp):
            oplist.append(__merge_block_content(it, consumer, nested=nested))
            continue
        clen = consumer(it)
        #print(it, clen)
        #如果parent已经是这样的block，或者不够用的时候（type cast的时候会出现）
        if idx == 0 and len(ast.oplist) <= (clen+1):
            clen = 0
        if clen != 0:
            new_op_list = []
            #print(ast, ast.oplist[idx:idx+clen+1])
            for it2 in ast.oplist[idx:idx+clen+1]:
                if nested:
                    if isinstance(it2, BlockOp):
                        new_op_list.append(__merge_block_content(it2, consumer, nested=nested))
                    else:
                        new_op_list.append(it2)
                else:
                    new_op_list.append(it2)
            oplist.append(BlockOp(new_op_list))
            #print(oplist[-1])
            idx += clen
        else:
            #oplist.append(it)
            oplist.append(__merge_block_content(it, consumer, nested=nested))
    return BlockOp(oplist)
